#pragma once
#include "matrix4.h"

#define TEMPLATE template<typename T>
#define MATRIX4 Matrix4T<T>

BEGIN_NAMESPACE_OXGE

TEMPLATE
const MATRIX4 MATRIX4::IDENTITY(1,0,0,0,
								0,1,0,0,
								0,0,1,0,
								0,0,0,1);

TEMPLATE
const MATRIX4 MATRIX4::ZERO( 0,0,0,0,
							 0,0,0,0,
							 0,0,0,0,
							 0,0,0,0 );



TEMPLATE
typename MATRIX4::SubMatrixType MATRIX4::GetSubMatrix(int r, int c)const
{		
	T mat2v[SubMatrixType::NCol * SubMatrixType::NRow];		
	size_t i2 = 0;
	for(size_t i=0;i< NRow; ++i)
	{
		if( i==r )continue;
		for(size_t j=0;j<NCol;++j)
		{
			if( j==c )continue;
			mat2v[i2] = (*this)(i,j);
			++i2;
		}
	}		
	return SubMatrixType(mat2v); 
}


TEMPLATE 
bool inverse(MATRIX4& dest, const MATRIX4& src)
{
	T detsrc = src.Det();
	if( detsrc == 0 )
	{
		return false;
	}

	if( &dest != &src )
	{
		for(size_t i=0;i<src.NRow;++i)
		{
			for(size_t j=0; j<src.NCol;++j)
			{
				dest(j,i) = ((i+j)%2==0?T(1):T(-1)) * src.GetSubMatrix(i,j).Det()/detsrc; 
			}
		}
	}
	else
	{
		MATRIX4 srccpy = src;
		for(size_t i=0;i<srccpy.NRow;++i)
		{
			for(size_t j=0; j<srccpy.NCol;++j)
			{
				dest(j,i) = ((i+j)%2==0 ?T(1):T(-1)) * srccpy.GetSubMatrix(i,j).Det() /detsrc; 
			}
		}
	}
	return true;
}

//global I/O
TEMPLATE
std::ostream& operator<<(std::ostream& os, const MATRIX4& mat)
{
	size_t iRow = 0;	
	for(;iRow < mat.NRow-1;++iRow){
		size_t iCol = 0;
		for(;iCol < mat.NCol-1 ; ++iCol){
			os << mat(iRow, iCol) << "\t";
		}
		os << mat(iRow, iCol);
		os << '\n';
	}
	size_t iCol = 0;
	for(;iCol < mat.NCol-1 ; ++iCol){
		os << mat(iRow, iCol) << "\t";
	}
	os << mat(iRow, iCol);
	os <<';';

	return os;
}

TEMPLATE
void MATRIX4::UnitTest()
{
	MatrixType mat;
	MatrixType mat1 = IDENTITY;
	MatrixType mat2 = ZERO;
	VectorType vec4;

	mat1 + mat2;

	mat1 * mat2;
	mat1^2;
	mat.GetInverse();
	mat.GetTranspose();
	mat * vec4;
	mat.Det();

}



END_NAMESPACE_OXGE


#undef TEMPLATE
#undef MATRIX4